/**
 * 模拟 VueRouter 的 hash 模式的实现，实现思路和 History 模式类似，
 * 把 URL 中的 # 后面的内容作为路由的地址，可以通过 hashchange 事件监听路由地址的变化。
 */

let _Vue = null
export default class VueRouter {
  // 由于vue.use()方法中如果传入一个对象的话，这个对象中要有 install 方法，所以我们在这里创建一个静态方法
  // 调用install方法的时候会传入连个参数，一个是vue的构造函数，
  static install (Vue) { // 传入vue的构造函数
    // 首先判断 是否已经安装了vuerouter插件
    if (VueRouter.install.installed) {
      return
    }
    VueRouter.install.installed = true

    // 把vue的构造函数记录到全局变量，后面routerlink，routerview的时候会用到
    _Vue = Vue
    // 把创建vue实例的时候传入的router对象注入到vue实例上
    _Vue.mixin({
      beforeCreate () {
        // 如果options属性中有 router的话代表的是Vue实例，如果没有代表组件
        if (this.$options.router) {
          // 这里我们给Vue 的原型挂载$router只需要执行一次，如果是组件的话就不让他执行，如果是Vue实例的话让他执行，所以这里多了一个判断
          _Vue.prototype.$router = this.$options.router
        }
      }
    })
  }

  constructor (options) { // 在这个构造函数中我们要初始化三个属性
    this.options = options
    this.routeMap = {
      // 作用：把options中传入的路由规则解析出来
    }
    this.data = _Vue.observable({
      current: '/' // 用来存储我们当前的路由地址，默认情况是/
    })
    this.init()
  }

  init () {
    this.createRouterMap()
    this.initComponents(_Vue)
    this.initEvent()
  }

  createRouterMap () {
    // 作用：遍历所有的路由规则。把路由规则解析成键值对的形式存储到routerMap中
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    })
  }

  initComponents (Vue) {
    // 创建 router-link 组件
    Vue.component('router-link', {
      // 接收一个参数to 用props来接收
      props: {
        to: String
        // eslint-disable-next-line vue/require-prop-type-constructor
      },
      // template: '<a :href="to"><slot></slot></a>'
      render (h) { // h函数的作用是帮我们创建虚拟dom
        return h('a', {
          attrs: { // 给a设置属性
            href: '#' + this.to
          },
          on: { // 给a设置的事件
            click: this.clickHandler
          }
        }, [this.$slots.default]) // 第三个参数为 设置生成元素的子元素 获取slots中的内容放到数组中去
      },
      methods: {
        clickHandler (e) {
          window.location.hash = '#' + this.to
          this.$router.data.current = this.to // 加载当前路径对应的组件
          e.preventDefault()
        }
      }
    })
    const self = this
    // 创建 router-view 组件
    Vue.component('router-view', {
      render (h) {
        const component = self.routeMap[self.data.current]
        return h(component) // 调用h函数把我们的组件转换成虚拟dom返回
      }
    })
  }

  initEvent () {
    window.addEventListener('hashchange', () => { // 当地址栏发生变化的时候触发的
      this.data.curent = window.location.hash.substr(1)
    })
  }
}
